﻿#region Copyright 
/*-------------------------------------------------------------------------
* 命名空间名称/文件名:    SSPivot.AspNetCore.Repository.DbContext/IDbLoadBalancer 
* CLR版本:     4.0.30319.42000
* 机器名称:    DESKTOP-NHMLO8A
* 功 能：       N/A
* 类 名：       IDbLoadBalancer
* 创建时间：  2025/6/3 15:01:27
* 版本号：      v1.0
* 创建人:        xulong
*-------------------------------------------------------------------------*/
#endregion
using Microsoft.Extensions.Configuration;
using SSPivot.AspNetCore.Config;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SSPivot.AspNetCore.Repository
{ 
    public interface IDbLoadBalancer
    {
        string GetReadConnection(DbConfig config); 
    }
    public class DbLoadBalancer : IDbLoadBalancer
    { 
        private int _currentIndex = 0;
        private readonly Random _random = new();

        public DbLoadBalancer()
        { 
        }

        public string GetReadConnection(DbConfig config)
        {
            if (config.SlaveDb.Count == 1)
                return config.SlaveDb[0];

            return config.Strategy switch
            {
                "RoundRobin" => GetRoundRobin(config),
                "Weighted" when config.Weights.Count == config.SlaveDb.Count => GetWeighted(config),
                _ => GetRandom(config)
            };
        }

        private string GetRandom(DbConfig config) =>
            config.SlaveDb[_random.Next(0, config.SlaveDb.Count)];

        private string GetRoundRobin(DbConfig config)
        {
            lock (this)
            {
                var connection = config.SlaveDb[_currentIndex];
                _currentIndex = (_currentIndex + 1) % config.SlaveDb.Count;
                return connection;
            }
        }

        private string GetWeighted(DbConfig config)
        {
            int totalWeight = config.Weights.Sum();
            int randomNumber = _random.Next(0, totalWeight);
            int cumulative = 0;

            for (int i = 0; i < config.Weights.Count; i++)
            {
                cumulative += config.Weights[i];
                if (randomNumber < cumulative)
                {
                    return config.SlaveDb[i];
                }
            }

            return config.SlaveDb[0];
        }
    }
}
